// ChessBoard.cpp: implementation of the CChessBoard class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Five.h"
#include "ChessBoard.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

const int GRID_SIZE = 30;
const int FOCUS_SIZE = 20;
const int CB_SX = 20;
const int CB_SY = 20;

CChessBoard::CChessBoard():m_size(CHESS_GRID_NUM)
{
}

CChessBoard::~CChessBoard()
{

}

void CChessBoard::Init()
{
	m_data.Init();
	m_currentPlayer = BLACK_CHESS;
}

void CChessBoard::DrawAll(CDC *pDC)
{
	//draw chess line first
	int xx,yy;
	xx = GRID_SIZE*(m_size-1)+CB_SX;
	yy = CB_SY;
	for(int y=0;y<m_size;++y)
	{
		pDC->MoveTo(CB_SX,yy);
		pDC->LineTo(xx,yy);
		yy += GRID_SIZE;
	}

	xx = CB_SX;
	yy = GRID_SIZE*(m_size-1)+CB_SY;
	for(int x=0;x<m_size;++x)
	{
		pDC->MoveTo(xx,CB_SY);
		pDC->LineTo(xx,yy);
		xx += GRID_SIZE;
	}


	//draw center point
	DrawMarkPoint(pDC,m_size/2,m_size/2);
	DrawMarkPoint(pDC,m_size/4,m_size/4);
	DrawMarkPoint(pDC,m_size/4,m_size*3/4);
	DrawMarkPoint(pDC,m_size*3/4,m_size/4);
	DrawMarkPoint(pDC,m_size*3/4,m_size*3/4);

	//draw chess
	for(x=0;x<m_size;++x)
	{
		for(y=0;y<m_size;++y)
		{
			if(m_data.Get(x,y)!=NONE_CHESS)
			{
				DrawChess(pDC,x,y);
			}
		}
	}
}

void CChessBoard::CoverChess(CDC *pDC, int x, int y)
{
	int xx = x*GRID_SIZE + CB_SX;
	int yy = y*GRID_SIZE + CB_SY;
	int radius = GRID_SIZE/2;
	
	CRect rect(xx-radius,yy-radius,xx+radius,yy+radius);
	
	COLORREF color = pDC->GetPixel(xx-radius,yy-radius);
	CBrush brush(color);
	CPen pen(PS_SOLID,1,color);
	CPen *pOldPen = pDC->SelectObject(&pen);
	CBrush* pOldBrush = pDC->SelectObject(&brush);
	pDC->Rectangle(&rect);
	pDC->SelectObject(pOldBrush);
	pDC->SelectObject(pOldPen);
}

void CChessBoard::DrawChess(CDC *pDC, int x, int y)
{
	char c = m_data.Get(x,y);

	int xx = x*GRID_SIZE + CB_SX;
	int yy = y*GRID_SIZE + CB_SY;
	int radius = GRID_SIZE/2;

	CRect rect(xx-radius,yy-radius,xx+radius,yy+radius);

	if(c == BLACK_CHESS)
	{
		CBrush black_brush(RGB(0,0,0));
        CBrush* pOldBrush = pDC->SelectObject(&black_brush);
		pDC->Ellipse(&rect);
        pDC->SelectObject(pOldBrush);
	}
	else if(c == WHITE_CHESS)
	{
		pDC->Ellipse(&rect);
	}
}

bool CChessBoard::GetPos(CPoint &pt,int &x, int &y)
{
	int xx = (pt.x - CB_SX+GRID_SIZE/2)/GRID_SIZE;
	int yy = (pt.y - CB_SY+GRID_SIZE/2)/GRID_SIZE;

	if(xx>=0 && xx<m_size && yy>=0 && yy<m_size)
	{
		x = xx; 
		y = yy;
		return true;
	}
	else
	{
		return false;
	}
}

int CChessBoard::PutChess(int x, int y)
{
	ASSERT(x>=0 && x<m_size);
	ASSERT(y>=0 && y<m_size);

	if(m_data.Get(x,y) == NONE_CHESS)
	{
		m_data.Set(x,y,m_currentPlayer);
		if(TestGameOver(x,y))
		{
			return 1;
		}
		else
		{
			SwitchPlayer();
			return 0;
		}
	}
	else
	{
		return -1;
	}
}

void CChessBoard::SwitchPlayer()
{
	m_currentPlayer = (m_currentPlayer==BLACK_CHESS?WHITE_CHESS:BLACK_CHESS);
}

void CChessBoard::DrawMarkPoint(CDC *pDC, int x, int y)
{
	int xx = x*GRID_SIZE + CB_SX;
	int yy = y*GRID_SIZE + CB_SY;
	int radius = 3;
	CRect rect(xx-radius,yy-radius,xx+radius,yy+radius);
	CBrush black_brush(RGB(0,0,0));
    CBrush* pOldBrush = pDC->SelectObject(&black_brush);
	pDC->Ellipse(&rect);
    pDC->SelectObject(pOldBrush);
}

void CChessBoard::FlashChess(CDC *pDC)
{
	static int tick=0,lastx=-1,lasty=-1;

	int x=-1,y=-1;
	ChessStep cs;
	if(m_data.GetLastStep(cs))
	{
		x=cs.x;y=cs.y;
	}
	else
	{
		return;
	}

	bool draw_chess = false;
	bool cover_chess = false;
	if(x!=lastx || y!=lasty)
	{
		tick = 0;//reset the tick
		if(lastx!=-1)
		{
			draw_chess =true;
		}
	}
	else
	{
		++tick;
		switch(tick%8)
		{
		case 0:
			draw_chess = true;
			break;
		case 7:
			cover_chess = true;
			break;
		default:
			break;
		}
	}

	if(draw_chess)
	{
		this->DrawChess(pDC,lastx,lasty);
	}
	if(cover_chess)
	{
		this->CoverChess(pDC,lastx,lasty);
	}

	lastx = x;
	lasty = y;
}

void CChessBoard::DrawFocusRect(CDC *pDC,CPoint &pt)
{
	static int lastx = -1,lasty = -1;
	int x=-1 , y=-1;
	bool clear_old = false,draw_new = false;
	
	if(GetPos(pt,x,y))
	{
		if(lastx != -1)
		{
			if(lastx!=x || lasty!=y)
			{
				clear_old = true;
				draw_new = true;
			}
		}
		else
		{
			draw_new = true;
		}
	}
	else
	{
		if(lastx !=-1)
		{
			clear_old = true;
		}
	}

	if(clear_old)
	{
		int xx = lastx*GRID_SIZE + CB_SX;
		int yy = lasty*GRID_SIZE + CB_SY;
		int radius = FOCUS_SIZE/2;
		CRect rect(xx-radius,yy-radius,xx+radius,yy+radius);
		pDC->GetWindow()->InvalidateRect(&rect);
	}

	if(x!=-1 && m_data.Get(x,y)!=NONE_CHESS)
	{
		draw_new = false;
	}

	if(draw_new)
	{
		int xx = x*GRID_SIZE + CB_SX;
		int yy = y*GRID_SIZE + CB_SY;
		int radius = FOCUS_SIZE/2;
		/*CBrush null_brush;
		CPen yellow_pen(PS_SOLID,1,RGB(255,0,0));
		null_brush.CreateStockObject(NULL_BRUSH);
		CPen* pOldPen = pDC->SelectObject(&yellow_pen);
        CBrush* pOldBrush = pDC->SelectObject(&null_brush);*/
		CRect rect(xx-radius,yy-radius,xx+radius,yy+radius);
		pDC->Rectangle(&rect);
		/*
		pDC->SelectObject(pOldBrush);
		pDC->SelectObject(pOldPen);*/
	}

	lastx = x;
	lasty = y;

}

bool CChessBoard::TestGameOver(int x,int y)
{
	if(TestGameOverHelper(x,y,1,0) + TestGameOverHelper(x,y,-1,0)>=4)
	{
		return true;
	}

	if(TestGameOverHelper(x,y,1,1) + TestGameOverHelper(x,y,-1,-1)>=4)
	{
		return true;
	}

	if(TestGameOverHelper(x,y,0,1) + TestGameOverHelper(x,y,0,-1)>=4)
	{
		return true;
	}

	if(TestGameOverHelper(x,y,1,-1) + TestGameOverHelper(x,y,-1,1)>=4)
	{
		return true;
	}

	return false;
}

int CChessBoard::TestGameOverHelper(int x,int y,int dx,int dy)
{
	int result = 0;
	for(int i=0;i<4;++i)
	{
		x += dx;
		y += dy;
		if(m_data.Get(x,y) == m_currentPlayer)
		{
			++result;
		}
		else
		{
			break;
		}
	}
	return result;
}


int CChessBoard::GetCurrentPlayer()
{
	return m_currentPlayer;
}




